﻿// D:\oshemesh\Visual Studio 2010\Projects\WPF_ResourceViewer\WPF_ResourceViewer\Stuff\Dictionary1.xaml
// C:\ccm_wa\ecs\EcsTop#800_oshemesh\EcsTop\Clients\Studio\Studio.Resources\ImagesResourceDictionary.xaml
// D:\oshemesh\Visual Studio 2010\Projects\WPF_ResourceViewer\WPF_ResourceViewer\Stuff\MergedSplitDict.xaml

using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Media;
using ResourceViewerExtension.Model;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Settings;
using Microsoft.VisualStudio.Shell.Settings;
using System.IO.IsolatedStorage;
using ResourceViewerExtension.Common;
using System.Runtime.InteropServices;
using System.Linq;
using System.Collections.Generic;
using System.Windows.Data;
using System.Xml;
using System.ComponentModel.Design;
using System.Windows.Input;
using System.Windows.Media.Imaging;

namespace ResourceViewerExtension
{
    public class MainViewModel : INotifyPropertyChanged
    {
        #region Ctor
        private MainViewModel()
        {
            mruManager = new MRUManager<string>(5);
            lcv = (ListCollectionView)CollectionViewSource.GetDefaultView(this.EntriesCollection);
            fileWatcher = new FileSystemWatcher();
            fileWatcher.NotifyFilter = NotifyFilters.LastWrite;
            fileWatcher.Changed += delegate
            {
                NotificationString = Resources.Resources.NotificationFileChanged;
            };


        }
        #endregion

        private const string PREFIX_KEY = "Prefix";
        private const string SUFFIX_KEY = "Suffix";

        private DTE dte;
        private int baseMRUID = (int)PkgCmdIDList.cmdidMRUCommand;
        private static MRUManager<string> mruManager;
        private ListCollectionView lcv;
        private FileSystemWatcher fileWatcher;

        public ICommand ToolWindowCreatedCommand { get { return new DelegateCommand(OnToolWindowCreated); } }
        public ICommand ViewUnLoadedCommand { get { return new DelegateCommand(ViewUnloaded); } }
        public ICommand Zoom16PresetCommand { get { return new DelegateCommand(Zoom16PresetClick); } }
        public ICommand Zoom32PresetCommand { get { return new DelegateCommand(Zoom32PresetClick); } }
        public ICommand ClearSearchCommand { get { return new DelegateCommand(ClearSearchButtonClick); } }
        public ICommand InjectCodeCommand { get { return new DelegateCommand(InjectCodeButtonClick); } }
        public ICommand CloseNotificationCommand { get { return new DelegateCommand(CloseNotificationClick); } }
        public ICommand ListBoxDoubleClickCommand { get { return new DelegateCommand(ListBoxDoubleClick); } }
        public ICommand LoadFilePathCommand { get { return new DelegateCommand(LoadFilePath); } }


        #region PrefixString property

        private string _PrefixString = "";
        public string PrefixString
        {
            get { return this._PrefixString; }
            set
            {
                if (this._PrefixString != value)
                {
                    this._PrefixString = value;
                    RaisePropertyChanged("PrefixString");
                }
            }
        }

        #endregion

        #region SuffixString property

        private string _SuffixString = "";
        public string SuffixString
        {
            get { return this._SuffixString; }
            set
            {
                if (this._SuffixString != value)
                {
                    this._SuffixString = value;
                    RaisePropertyChanged("SuffixString");
                }
            }
        }

        #endregion

        #region FilePathString property

        private string _FilePathString;
        public string FilePathString
        {
            get { return this._FilePathString; }
            set
            {
                if (this._FilePathString != value)
                {
                    this._FilePathString = value;
                    RaisePropertyChanged("FilePathString");
                }
            }
        }

        #endregion

        #region EntriesCollection property

        private ObservableCollection<EntryModel> _EntriesCollection = new ObservableCollection<EntryModel>();
        public ObservableCollection<EntryModel> EntriesCollection
        {
            get { return this._EntriesCollection; }
            set
            {
                if (this._EntriesCollection != value)
                {
                    this._EntriesCollection = value;

                    RaisePropertyChanged("EntriesCollection");
                }
            }
        }

        #endregion

        #region ZommSliderValue property

        private int _ZommSliderValue = 48;
        public int ZommSliderValue
        {
            get { return this._ZommSliderValue; }
            set
            {
                if (this._ZommSliderValue != value)
                {
                    this._ZommSliderValue = value;
                    RaisePropertyChanged("ZommSliderValue");
                }
            }
        }

        #endregion

        #region SearchString property

        private string _SearchString = "";
        public string SearchString
        {
            get { return this._SearchString; }
            set
            {
                if (this._SearchString != value)
                {
                    this._SearchString = value;
                    lcv.Filter = FilterPredicate;
                    RaisePropertyChanged("SearchString");
                }
            }
        }

        #endregion

        #region NotificationString property

        private string _NotificationString;
        public string NotificationString
        {
            get { return this._NotificationString; }
            set
            {
                if (this._NotificationString != value)
                {
                    this._NotificationString = value;
                    RaisePropertyChanged("NotificationString");
                }
            }
        }

        #endregion

        #region Methods called from toolbar
        private void OpenFileButtonCommand(object sender, EventArgs e)
        {
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.Filter = "Resource Dictionary|*.xaml"; // Filter files by extension

            Nullable<bool> result = dlg.ShowDialog();

            if (result == true)
            {
                LoadFile(dlg.FileName);
            }
        }

        private void RefreshButtonCommand(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(FilePathString))
            {
                LoadFile(FilePathString, true);
            }
        }
        #endregion

        #region Methods called from view
        private void CloseNotificationClick(object obj)
        {
            NotificationString = "";
        }

        private void ClearSearchButtonClick(object obj)
        {
            SearchString = string.Empty;
        }

        private void OnToolWindowCreated(object obj)
        {
            var serviceProvider = obj as IServiceProvider;

            if (dte == null)
                dte = serviceProvider.GetService(typeof(DTE)) as DTE;

            if (mruManager.List.Count > 0)
            {
                LoadFile(mruManager.List[0]);
            }

            UserSettingsManager.LoadSettings();
            string str;
            if (UserSettingsManager.Settings.TryGetValue(PREFIX_KEY, out str))
            {
                PrefixString = str;
            }
            if (UserSettingsManager.Settings.TryGetValue(SUFFIX_KEY, out str))
            {
                SuffixString = str;
            }

            var mcs = serviceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
            CommandID openFileCommand = new CommandID(GuidList.guidResourceViewerExtensionCmdSet, PkgCmdIDList.cmdidOpenFileCommand);
            mcs.AddCommand(new MenuCommand(OpenFileButtonCommand, openFileCommand));

            for (int i = 0; i < mruManager.List.Count; i++)
            {
                var mruCmdId = new CommandID(GuidList.guidResourceViewerExtensionCmdSet, this.baseMRUID + i);
                var mruCommand = new OleMenuCommand(OnMRUItemExec, mruCmdId);
                mruCommand.BeforeQueryStatus += new EventHandler(OnMRUQueryStatus);
                mcs.AddCommand(mruCommand);
            }

            CommandID refreshCommand = new CommandID(GuidList.guidResourceViewerExtensionCmdSet, PkgCmdIDList.cmdidRefreshCommand);
            mcs.AddCommand(new MenuCommand(RefreshButtonCommand, refreshCommand));
        }

        private void ViewUnloaded(object obj)
        {
            Dictionary<string, string> settings = new Dictionary<string, string>();
            settings.Add(PREFIX_KEY, PrefixString);
            settings.Add(SUFFIX_KEY, SuffixString);

            if (settings.Count > 0)
                UserSettingsManager.SaveSettings(settings);
        }

        private void ListBoxDoubleClick(object obj)
        {
            InsertSelectionIntoActiveDoc();
        }

        private void InjectCodeButtonClick(object obj)
        {
            InsertSelectionIntoActiveDoc();
        }

        private void Zoom16PresetClick(object obj)
        {
            ZommSliderValue = 16;
        }

        private void Zoom32PresetClick(object obj)
        {
            ZommSliderValue = 32;
        }
        #endregion

        #region Methods
        private void LoadFilePath(object obj)
        {
            LoadFile(obj as string);
        }

        private bool FilterPredicate(object obj)
        {
            var de = (EntryModel)obj;
            bool nameFilter = de.Key.ToString().ToLower().Contains(SearchString.ToLower());
            return nameFilter;
        }

        private void InsertSelectionIntoActiveDoc()
        {
            var str = String.Format("{0}{1}{2}", PrefixString, (lcv.CurrentItem as EntryModel).Key, SuffixString);

            Document doc = dte.ActiveDocument;
            if (doc == null)
            {
                NotificationString = Resources.Resources.NotificationNoOpenedDoc;
                return;
            }

            TextSelection ts = doc.Selection as TextSelection;
            ts.Insert(str);
            doc.Activate();

            if (NotificationString == Resources.Resources.NotificationNoOpenedDoc)
                NotificationString = "";
        }

        private void LoadFile(string path, bool isRefresh = false)
        {
            if (string.IsNullOrEmpty(path))
                return;

            try
            {
                string selectedEntryKey = "";
                fileWatcher.EnableRaisingEvents = false;
                NotificationString = "";

                FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);

                ResourceDictionary rd = (ResourceDictionary)XamlReader.Load(fs);

                if (isRefresh)
                {
                    selectedEntryKey = (lcv.CurrentItem as EntryModel).Key;
                }

                ResetOpenedData();
                UpdateSource(rd);

                if (isRefresh)
                {
                    lcv.MoveCurrentTo(EntriesCollection.FirstOrDefault(p => p.Key == selectedEntryKey));
                }
                else
                {
                    mruManager.Add(path);
                    lcv.MoveCurrentToFirst();
                }

                FilePathString = path;
                fileWatcher.Path = Path.GetDirectoryName(FilePathString);
                fileWatcher.Filter = Path.GetFileName(FilePathString);
                fileWatcher.EnableRaisingEvents = true;

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void UpdateSource(ResourceDictionary rd)
        {
            foreach (DictionaryEntry item in rd)
            {
                // TODO [shemesh] add handling for those types.
                if (item.Value is ImageBrush || item.Value is BitmapImage)
                    continue;

                if (item.Value is ImageSource || item.Value is Brush)
                {
                    string src = "Main Dictionary";
                    if (rd.Source != null)
                        src = rd.Source.ToString();
                    var em = new EntryModel(item, src);
                    EntriesCollection.Add(em);
                }
            }
        }

        private void ResetOpenedData()
        {
            EntriesCollection.Clear();
            FilePathString = "";
        }

        private void OnMRUQueryStatus(object sender, EventArgs e)
        {
            OleMenuCommand menuCommand = sender as OleMenuCommand;
            if (menuCommand != null)
            {
                int MRUItemIndex = menuCommand.CommandID.ID - this.baseMRUID;
                if (MRUItemIndex >= 0 && MRUItemIndex < mruManager.List.Count)
                {
                    string path = mruManager.List[MRUItemIndex] as string;
                    menuCommand.Text = ShortenPathHelper.ShortenPath(path, 300);
                }
            }
        }

        private void OnMRUItemExec(object sender, EventArgs e)
        {
            var menuCommand = sender as OleMenuCommand;
            if (menuCommand != null)
            {
                int MRUItemIndex = menuCommand.CommandID.ID - this.baseMRUID;
                if (MRUItemIndex >= 0 && MRUItemIndex < mruManager.List.Count)
                {
                    string selection = mruManager.List[MRUItemIndex] as string;
                    LoadFile(selection);
                }
            }
        }

        #endregion

        #region Singleton
        private static MainViewModel instance;
        public static MainViewModel Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new MainViewModel();
                }
                return instance;
            }
        }
        #endregion

        #region INotify
        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

    }
}
